package org.noote.test_computervision_duo;

import java.text.DecimalFormat;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;

import org.noote.libs.camera.surface.CameraSurface;
import org.noote.libs.camera.helper.Helper_Camera;
import org.noote.libs.computervision.buffer.Buffer8888XRGB;
import org.noote.libs.computervision.detection.edge.SobelDetection;
import org.noote.libs.computervision.detection.movement.MovementDetection_Grid;
import org.noote.libs.computervision.detection.movement.MovementDetection_Map;
import org.noote.libs.computervision.math.Point2D;
import org.noote.libs.graphicbuffer.GraphicBuffer;
import org.noote.libs.graphicbuffer.GraphicView;
import org.noote.libs.graphicbuffer.FPSCounter;

@SuppressLint("HandlerLeak")
public class TestComputerVision_Activity extends Activity {
	protected static final int MSG_UPDATE_FPSCOUNTER = 0;
	
	private CameraSurface _camera = new CameraSurface();;
	
	private OutputView _ouputView;
	private CameraView _cameraView;
	
	private FPSCounter _fpsCapture = new FPSCounter();
	private FPSCounter _fpsComputed = new FPSCounter();
	
	private enum CV_Mode {CAMERA, INTENSITY, SOBEL_3x3, MOVEMENT_MAP, MOVEMENT_GRID};
	private CV_Mode _cvMode = CV_Mode.CAMERA;
	
	protected  final Lock viewComputedLock = new ReentrantLock();
	
	Buffer8888XRGB _frameInXRGB = new Buffer8888XRGB();
	Buffer8888XRGB _frameOutXRGB = new Buffer8888XRGB();
	SobelDetection _frameSobel = new SobelDetection();
	MovementDetection_Map _frameMovementMap = new MovementDetection_Map();
	MovementDetection_Grid _frameMovementGrid = new MovementDetection_Grid(3*3, 4*3);
	GraphicBuffer _frameGraphic = new GraphicBuffer();

	public class OutputView extends GraphicView {
		
		public OutputView(Context context) {
	        super(context);
	    }
		
		@Override
		protected void onSizeChanged(int width, int height, int width_old, int height_old)
		{
			super.onSizeChanged(width, height, width_old, height_old);

			createBuffer(width, height);
		}
	}
	public class CameraView extends GraphicView {
		
		public CameraView(Context context) {
	        super(context);
	    }
		
		@Override
		protected void onSizeChanged(int width, int height, int width_old, int height_old)
		{
			super.onSizeChanged(width, height, width_old, height_old);

			createBuffer(width, height);
		}
	}	
	
	public class CameraPreviewListener implements org.noote.libs.camera.listener.CameraPreviewListener {
		@Override
		public void onStartPreview() {
		}

		@Override
		public void onGrabbedFrame(GraphicBuffer frameCamera) {
			// image de reference
			_cameraView.push(frameCamera);
			
			if (viewComputedLock.tryLock()) {
				try {

					// image de sortie
					switch(_cvMode)
					{
					case INTENSITY:
						if(_frameInXRGB.createFrom(frameCamera))
						{
							_frameSobel.calculIntensityFrom(_frameInXRGB);
							
							// push frame !
							_frameSobel.exportTo(_frameOutXRGB);
							_frameOutXRGB.copyTo(_frameGraphic);
							_ouputView.push(_frameGraphic);
						}
						break;
					case SOBEL_3x3:
						if(_frameInXRGB.createFrom(frameCamera))
						{
							_frameSobel.do3x3(_frameInXRGB, 25);
							
							// push frame !
							_frameSobel.exportEdgeTo(_frameOutXRGB);
							_frameOutXRGB.copyTo(_frameGraphic);
							_ouputView.push(_frameGraphic);
						}
						break;
					case MOVEMENT_MAP:
						if(_frameInXRGB.createFrom(frameCamera))
						{
							_frameMovementMap.push(_frameInXRGB, _fpsComputed.getTimeSlice());
							
							// push frame !
							_frameMovementMap.exportTo(_frameOutXRGB);
							_frameOutXRGB.copyTo(_frameGraphic);
							_ouputView.push(_frameGraphic);
						}
						break;
					case MOVEMENT_GRID:
						if(_frameInXRGB.createFrom(frameCamera))
						{
							_frameMovementGrid.push(_frameInXRGB, _fpsComputed.getTimeSlice());
							
							// get frame
							_frameInXRGB.fill(0x000000);
							_frameInXRGB.add(_frameMovementGrid);
							int iColumnSize = _frameInXRGB.getWidth()/_frameMovementGrid.getColumnCount();
							int iRowSize = _frameInXRGB.getHeight()/_frameMovementGrid.getRowCount();
							for(int y=0; y<_frameMovementGrid.getRowCount(); y++)
							{
								for(int x=0; x<_frameMovementGrid.getColumnCount(); x++)
								{
									float fA = _frameMovementGrid.getActivity(x, y); 
									if(fA>0.25f)
									{
										_frameInXRGB.drawFilledRect(new Point2D(iColumnSize*x+1, iRowSize*y+1), new Point2D(iColumnSize-1, iRowSize-1), 0x00FF1F1F);
									}
									else
									{
										_frameInXRGB.drawRect(new Point2D(iColumnSize*x, iRowSize*y), new Point2D(iColumnSize, iRowSize), 0x00FF0000);
									}
								}
							}
							
							// push frame !
							_frameInXRGB.copyTo(_frameGraphic);
							_ouputView.push(_frameGraphic);
						}
						break;
					case CAMERA:
					default:
						_ouputView.push(frameCamera);
						break;
					}
					
					_fpsCapture.tick();
				} finally {
					viewComputedLock.unlock();
				}
			}
			
			_fpsComputed.tick();
			mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_FPSCOUNTER, null));					
		}

		@Override
		public void onStopPreview() {
		}
	}
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		if(Helper_Camera.checkCameraHardware(getApplicationContext()))
		{
			_camera.setPreviewListener(new CameraPreviewListener());
		}
		else
		{
			Toast.makeText(getApplicationContext(), "Your device have no camera !", Toast.LENGTH_LONG).show();
		}

		_ouputView = new OutputView(this);
		((FrameLayout) findViewById(R.id.layoutOutput)).addView(_ouputView);
		
		_cameraView = new CameraView(this);
		((FrameLayout) findViewById(R.id.layoutCamera)).addView(_cameraView);

		Spinner spinnerEffect = (Spinner) findViewById(R.id.spinnerEffect);
		spinnerEffect.setOnItemSelectedListener(new OnItemSelectedListener()
		{
			@Override
			public void onItemSelected(AdapterView<?> arg0, View arg1,
					int arg2, long arg3) {
				
				if(arg2 == 1)
					_cvMode = CV_Mode.INTENSITY;
				else if(arg2 == 2)
					_cvMode = CV_Mode.SOBEL_3x3;
				else if(arg2 == 3)
					_cvMode = CV_Mode.MOVEMENT_MAP;
				else if(arg2 == 4)
					_cvMode = CV_Mode.MOVEMENT_GRID;
				else
					_cvMode = CV_Mode.CAMERA;
			}

			@Override
			public void onNothingSelected(AdapterView<?> arg0) {
				_cvMode = CV_Mode.CAMERA;
			}
		});
		spinnerEffect.setSelection(4);
	}

	@Override
    protected void onResume() {
        super.onResume();
		if(_camera.open(Helper_Camera.getCamera()))
		{
			_camera.startPreview();
		}
		else
		{
			Toast.makeText(getApplicationContext(), "Cannot open camera !", Toast.LENGTH_LONG).show();
		}
    }

	@Override
    protected void onPause() {
		_camera.close();
		
        super.onPause();        
    }

	final Handler mHandler = new Handler() {
		DecimalFormat m_dfFPS = new DecimalFormat("#,##0.00");
		
	    @Override
		public void handleMessage(Message msg) {
	        switch (msg.what) {
	        case MSG_UPDATE_FPSCOUNTER:
	        	TextView textCaptureFPS = (TextView) findViewById(R.id.textCaptureFPS);
	        	textCaptureFPS.setText(m_dfFPS.format(_fpsCapture.getFPS()) + " f/s");
	        	
	        	TextView textOuputFPS = (TextView) findViewById(R.id.textOuputFPS);
	        	textOuputFPS.setText(m_dfFPS.format(_fpsComputed.getFPS()) + " f/s");
	            break;
	        }
	    }
	};

}
